import archiver from 'archiver'
import { execSync, spawn } from 'child_process'
import fs from 'fs'
import inquirer from 'inquirer'
import os from 'os'
import path from 'path'
import { fileURLToPath } from 'url'

const __finename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__finename)

const PRODUCT_NAME = 'Fantasi'

async function askQuestions() {
  const packagePath = path.join(__dirname, '../package.json')
  const packageContent = fs.readFileSync(packagePath, 'utf-8')
  const latestVersion = packageContent.match(/"version":\s*['"`](\d+\.\d+\.\d+)['"`]/)[1]

  console.log(`當前版本: v${latestVersion}`)
  const answers = await inquirer.prompt([
    {
      type: 'input',
      name: 'version',
      message: `請輸入此次要發布的版本號(不含"v")(當前版本: v${latestVersion}):`,
      validate: (input) => /^\d+\.\d+\.\d+$/.test(input) || '請輸入有效的版本號，比如 1.0.0',
    },
    {
      type: 'select',
      name: 'enviroment',
      message: '請輸入此次要發布的環境(正式/測試/全部):',
      choices: ['production', 'testing', 'All'],
    },
  ])

  return answers
}

async function askPreview() {
  const answers = await inquirer.prompt([
    {
      type: 'confirm',
      name: 'preview',
      message: '是否要預覽此次發布的內容?',
    },
  ])

  return answers
}

async function updatePackageVersion(version) {
  const packagePath = path.join(__dirname, '../package.json')
  const packageContent = fs.readFileSync(packagePath, 'utf-8')
  const replacement = packageContent.replace(/"version":\s*['"`]\d+\.\d+\.\d+['"`]/, `"version": "${version}"`)
  fs.writeFileSync(packagePath, replacement)
}

async function updateEnvVersion({ version, env }) {
  const envName = env === 'production' ? '.env.production' : '.env.staging'
  const envPath = path.join(__dirname, `../${envName}`)
  const envContent = fs.readFileSync(envPath, 'utf-8')

  const replacement = envContent.replace(/VITE_APP_VERSION=\s*\d+\.\d+\.\d+/, `VITE_APP_VERSION=${version}`)
  fs.writeFileSync(envPath, replacement)
}

function buildProject(env) {
  const command = env === 'production' ? 'npm run build' : 'npm run build:staging'
  execSync(command, { stdio: 'inherit' })
}

function zipFiles(version, env) {
  const outputFileName = `${PRODUCT_NAME}-v${version}-${env}.zip`
  const outputFilePath = path.join(__dirname, '../', outputFileName)
  const downloadPath = path.join(os.homedir(), 'Downloads', outputFileName)

  const output = fs.createWriteStream(outputFilePath)

  const archive = archiver('zip', { zlib: { level: 9 } })
  const archiveFolder = env === 'production' ? 'dist' : 'dist-staging'
  const archivePath = path.join(__dirname, `../${archiveFolder}`)

  return new Promise((resolve, reject) => {
    output.on('close', () => {
      fs.renameSync(outputFilePath, downloadPath)
      const filesize = (archive.pointer() / 1000000).toFixed(2)
      console.log(`${outputFileName} 壓縮完成，共 ${filesize} MB, 已轉移到 Downloads 資料夾`)
      resolve(downloadPath)
    })
    output.on('error', (err) => reject(err))

    archive.pipe(output)
    archive.directory(archivePath, archiveFolder)
    archive.finalize()
  }).catch((err) => {
    throw err
  })
}

function generateReport(version, env) {
  const envStr = env === 'production' ? '正式' : env === 'testing' ? '測試' : '正式/測試'
  const lastTag = execSync('git describe --tags --abbrev=0').toString().trim()

  const command =
    os.platform() === 'win32'
      ? `git log ${lastTag}..HEAD --oneline --format="%s" | Select-String -NotMatch "Merge"`
      : `git log ${lastTag}..HEAD --oneline --format="%s" | grep -v "Merge"`

  const gitLogs = execSync(command)

  let gitLogsStr = ''
  if (gitLogs.length > 0) {
    gitLogsStr = gitLogs
      .toString()
      .trim()
      .split('\n')
      .map((log, index) => `${index + 1}. ${log}`)
      .join('\n')
  } else {
    gitLogsStr = '無'
  }

  const reportContent = `
  ${PRODUCT_NAME} 部版報告
  版本: v${version}
  前次版本: ${lastTag}
  發布日期: ${new Date().toLocaleDateString('sv')}
  發布環境: ${envStr}
  更新內容:
  ${gitLogsStr}
  `

  const reportDir = path.join(__dirname, '../reports')
  if (!fs.existsSync(reportDir)) fs.mkdirSync(reportDir)

  const reportPath = path.join(reportDir, `deploy-v${version}.md`)
  fs.writeFileSync(reportPath, reportContent)

  console.log(`版本報告已生成: ${reportPath}`)
}

function startPreview() {
  console.log(`正在啟動預覽程序...`)
  const previewProcess = spawn('npm', ['run', 'preview:staging'], { stdio: 'inherit' })
  previewProcess.on('close', (code) => console.log(`預覽程序已退出，退出碼: ${code}`))
  previewProcess.on('exit', (code) => console.log(`預覽程序已退出，退出碼: ${code}`))
  previewProcess.on('message', (message) => console.log(`預覽程序發送消息: ${message}`))
}

async function main() {
  const { version, enviroment } = await askQuestions()
  updatePackageVersion(version)

  const envs = enviroment === 'All' ? ['production', 'testing'] : [enviroment]
  for (const env of envs) {
    await updateEnvVersion({ version, env })
    buildProject(env)
    await zipFiles(version, env)
  }

  generateReport(version, enviroment)
  console.log(`
    🎉🎉🎉 發布完成 🎉🎉🎉\n
    請至 reports 資料夾查看版本報告\n
    記得手動將部署內容 commit 到遠端倉庫😎\n
    `)

  const { preview } = await askPreview()
  if (preview) startPreview()
}

main()
  .catch(console.error)
  .finally(() => console.log('發布程序已退出'))
